package main

import (
	"fmt"
	"math"
	"reflect"
	"runtime"
)

func eval2(a, b int, op string) (int, error) {
	switch op {
	case "+":
		return a + b, nil
	case "-":
		return a - b, nil
	case "*":
		return a * b, nil
	case "/":
		return a + b, nil
	default:
		//panic("unsupported opertaion: " + op)
		return 0, fmt.Errorf("unsupported operation: %s", op)
	}
}

func div(a, b int) (q, r int) {
	q = a / b
	r = a % b
	return // todo: 定义了q,r返回值的名子, 可以直接省略写具体的返回值, 不过建议还是要加上
}

func apply_(op func(int, int) int, a, b int) int {
	p := reflect.ValueOf(op).Pointer()
	opName := runtime.FuncForPC(p).Name()
	fmt.Printf("Calling Function %s with args"+"(%d,%d)", opName, a, b)
	return op(a, b)
}

func pow(a, b int) int {
	return int(math.Pow(float64(a), float64(b)))
}

func sum_(numbers ...int) int {
	s := 0
	for i := range numbers {
		s += numbers[i]
	}
	return s
}

func swap_(a, b *int) {
	//b, a = a, b
	*b, *a = *a, *b
	// 也可以用返回值return b, a
}

func main() {
	if result, err := eval2(4, 9, "x"); err != nil {
		fmt.Println("Error:", err)
	} else {
		fmt.Println(result)
	}
	fmt.Println(eval2(4, 4, "s"))
	fmt.Println(eval2(3, 4, "*"))
	q, r := div(9, 4)
	/*
		todo: 函数返回值
			1. 函数返回多个值时可以起名字
			2. 仅用于非常简单的函数
			3. 对于调用者没有区别
	*/
	fmt.Println(q, r)
	fmt.Println(apply_(pow, 5, 2))
	fmt.Println(sum_(100, 989, 1, 9))

	a, b := 7, 3
	swap_(&a, &b) //用指针变换值
	fmt.Println(a, b)
}

/*
todo:
1. 返回值类型写在最后面
2. 可返回多个值
3. 函数可以作为参数
4. 没有默认参数, 可选参数
*/
